package com.dsteiner.gwt.cafeteriasophia.client.controller;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.commons.httpclient.util.DateUtil;

import com.dsteiner.gwt.cafeteriasophia.client.domain.Change;
import com.dsteiner.gwt.cafeteriasophia.client.domain.Product;
import com.dsteiner.gwt.cafeteriasophia.client.domain.Purchase;
import com.dsteiner.gwt.cafeteriasophia.client.domain.Sale;
import com.dsteiner.gwt.cafeteriasophia.client.domain.ShiftChange;
import com.dsteiner.gwt.cafeteriasophia.client.domain.Stock;
import com.dsteiner.gwt.cafeteriasophia.client.event.AddShiftChangeEvent;
import com.dsteiner.gwt.cafeteriasophia.client.event.ChangesEvent;
import com.dsteiner.gwt.cafeteriasophia.client.event.CheckShiftChangeEvent;
import com.dsteiner.gwt.cafeteriasophia.client.event.NavEvent;
import com.dsteiner.gwt.cafeteriasophia.client.model.NavModel;
import com.dsteiner.gwt.cafeteriasophia.client.model.ProductModel;
import com.dsteiner.gwt.cafeteriasophia.client.model.ShiftChangeModel;
import com.dsteiner.gwt.cafeteriasophia.client.rpc.DataService;
import com.dsteiner.widgets.client.DateUtilImpl;
import com.dsteiner.widgets.client.JsUtil;
import com.dsteiner.widgets.client.Widgets.IHTML;
import com.dsteiner.widgets.client.Widgets.ILazyWidget;
import com.dsteiner.widgets.client.Widgets.IWidget;
import com.dsteiner.widgets.client.Widgets.WidgetListenerAdapter;
import com.dsteiner.widgets.client.domain.Sort;
import com.dsteiner.widgets.client.event.EventListener;
import com.dsteiner.widgets.client.event.EventManager;
import com.dsteiner.widgets.client.event.EventManagerImpl;
import com.dsteiner.widgets.client.model.PrefilledTextBoxModel;
import com.dsteiner.widgets.client.rpc.SearchRequest;
import com.dsteiner.widgets.client.rpc.SearchResult;
import com.dsteiner.widgets.client.rpc.SearchRequest.SearchRequestImpl;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.rpc.AsyncCallback;

public class ShiftChangeEditController {

	public static double getTotalValueChange(final ShiftChange shiftChange,
			ShiftChange lastShiftChange, StringBuffer sb, List<Change> changes) {
		double salesSum = 0;
		double iceCreamWeightSumOnz = 0;
		double cocktailWeightSumMl = 0;
		double stockableProductValueChanges = 0;
		
		for (int i = 0; i < Product.products.length; i++) {
			Product product = Product.products[i];
			double productSalesSum = shiftChange.getSalesSum(product);
			if(product.isStockable() && product.isSaleable()){
				// add pepsi floats to gaseosa sales
				if(product.equals(Product.gaseosa))
					productSalesSum += shiftChange.getSalesSum(Product.pepsiFloat);
				// add smoothie to california sales
				if(product.equals(Product.california))
					productSalesSum += shiftChange.getSalesSum(Product.smoothie);
				double productPurchasesSum = shiftChange.getPurchasesSum(product);
				double productStockChange = shiftChange.getStockSum(product) - 
				lastShiftChange.getStockSum(product);
				double productCalcChange = productPurchasesSum - productSalesSum;
				double productAmountChange = productStockChange - productCalcChange;
				double valueChange = productAmountChange * product.getDefaultPrice();
				stockableProductValueChanges += valueChange;
				if(valueChange != 0){
					sb.append(product.getName()).append(":").append(productAmountChange).
					append(" ").append(product.getMetric()).append("<br>");
					changes.add(new Change(product, productAmountChange));
				}
			}
			Double iceCreamWeight = product.getIceCreamWeight();
			if(iceCreamWeight != null){
				iceCreamWeightSumOnz += iceCreamWeight * productSalesSum;
			}
			Double cocktailWeight = product.getCocktailWeight();
			if(cocktailWeight != null){
				cocktailWeightSumMl += cocktailWeight * productSalesSum;
			}
			salesSum += shiftChange.getSalesValue(product);
		}
		
		double moneyCalcChange = salesSum  + shiftChange.getSalesSum(Product.dinero) - shiftChange.getPurchasesSum(Product.dinero);
		double moneyStockChange = shiftChange.getStockSum(Product.dinero) - 
		lastShiftChange.getStockSum(Product.dinero);
		double moneyChange = moneyStockChange - moneyCalcChange;
		if(moneyChange != 0){
			sb.append(Product.dinero.getName()).append(": Q ").append(moneyChange).append("<br>");
			changes.add(new Change(Product.dinero, moneyChange));
		}
		
		double telephoneValueIncrease = shiftChange.getPurchasesSum(Product.inventarioTarjetas) * 0.05;
		double telephoneChange = shiftChange.getStockSum(Product.inventarioTarjetas) - 
		(lastShiftChange.getStockSum(Product.inventarioTarjetas) + telephoneValueIncrease);
		if(telephoneChange < 0){
			sb.append(Product.inventarioTarjetas.getName()).append(": Q ").append(telephoneChange).append("<br>");
			changes.add(new Change(Product.inventarioTarjetas, telephoneChange));
		}
		else
			telephoneChange = 0;
		
		double iceCreamCalcChange = shiftChange.getPurchasesSum(Product.helados) - iceCreamWeightSumOnz/16;
		double iceCreamStockChange = shiftChange.getStockSum(Product.helados) - 
		lastShiftChange.getStockSum(Product.helados);
		double iceCreamAmountChange = iceCreamStockChange - iceCreamCalcChange;
		double iceCreamValueChange = iceCreamAmountChange * Product.helados.getDefaultPrice();
		if(iceCreamAmountChange != 0){
			sb.append(Product.helados.getName()).append(":").append(iceCreamAmountChange)
			.append(" ").append(Product.helados.getMetric()).append("<br>");
			changes.add(new Change(Product.helados, iceCreamAmountChange));
		}
		
		double cocktailsCalcChange = shiftChange.getPurchasesSum(Product.cocktails) - cocktailWeightSumMl*0.02125;
		double cocktailsStockChange = shiftChange.getStockSum(Product.cocktails) - 
		lastShiftChange.getStockSum(Product.cocktails);
		double cocktailAmountChange = cocktailsStockChange - cocktailsCalcChange;
		double cocktailsValueChange = cocktailAmountChange * Product.cocktails.getDefaultPrice(); 
		if(cocktailAmountChange != 0){
			sb.append(Product.cocktails.getName()).append(":").append(cocktailAmountChange)
			.append(" ").append(Product.cocktails.getMetric()).append("<br>");
			changes.add(new Change(Product.cocktails, cocktailAmountChange));
		}

		final double totalValueChange = moneyChange + iceCreamValueChange + cocktailsValueChange + 
		stockableProductValueChanges + telephoneChange;
		return totalValueChange;
	}
	
	private ShiftChangeModel shiftChangeModel;
	private PrefilledTextBoxModel dateTextBoxModel;
	private PrefilledTextBoxModel employeeTextBoxModel;
	private List<ProductModel> productModels = new ArrayList<ProductModel>();

	public void registerDateTextBoxModel(final PrefilledTextBoxModel dateTextBoxModel) {
		this.dateTextBoxModel = dateTextBoxModel;
	}

	public void registerEmployeeTextBoxModel(final PrefilledTextBoxModel employeeTextBoxModel) {
		this.employeeTextBoxModel = employeeTextBoxModel;
	}

	public void registerEventManager(EventManager eventManager) {
		eventManager.registerListener(CheckShiftChangeEvent.class, new EventListener<CheckShiftChangeEvent>(){
			public void onEvent(CheckShiftChangeEvent event) {
				ShiftChange shiftChange = shiftChangeModel.getShiftChange();
				StringBuffer sb = new StringBuffer();
				if(!employeeTextBoxModel.isEdited())
					sb.append("ingrese el nombre de la encargado\n");
				
				Date date = DateUtilImpl.getInstance().parseDateSpanish(dateTextBoxModel.getText());
				if(!dateTextBoxModel.isEdited())
					sb.append("ingrese la fecha del cambio de turno\n");
				else if(date == null)
					sb.append("ingrese la fecha en el formato de por ejemplo 26/03/2009\n");
				
				if(sb.length() > 0){
					JsUtil.getInstance().showAlert(sb.toString());
					return;
				}
				
				List<Purchase> purchases = new ArrayList<Purchase>();
				List<Sale> sales = new ArrayList<Sale>();
				List<Stock> stocks = new ArrayList<Stock>();
				for (ProductModel productModel : productModels) {
					Product product = productModel.getProduct();
					for (Purchase purchase : productModel.getPurchases()) {
						if(purchase.getAmount() != 0)
							purchases.add(purchase);
					}
					for (Sale sale : productModel.getSales()) {
						if(sale.getAmount() != 0)
							sales.add(sale);
					}
					Stock stock = productModel.getStock();
					if(stock.getAmount() != 0)
						stocks.add(stock);
				}
				shiftChange.setEmployee(employeeTextBoxModel.getText());
				shiftChange.setDate(date);
				shiftChange.setPurchases(purchases);
				shiftChange.setSales(sales);
				shiftChange.setStocks(stocks);
				
				ShiftChange lastShiftChange = shiftChangeModel.getLastShiftChange();
				if(lastShiftChange != null){
					List<Change> changes = new ArrayList<Change>();
					final double totalValueChange = getTotalValueChange(shiftChange, lastShiftChange, sb, changes);
					if(!changes.isEmpty()){
						EventManagerImpl.getInstance().fireEvent(new ChangesEvent(changes, productModels, 
								totalValueChange, shiftChange));
						return;
					}
				}
				EventManagerImpl.getInstance().fireEvent(new AddShiftChangeEvent(shiftChange));
			}
		});
	}

	public void registerNavLink(IHTML navLink) {
		navLink.addClickHandler(new ClickHandler(){
			public void onClick(ClickEvent event) {
				EventManagerImpl.getInstance().fireEvent(new NavEvent(NavModel.PAGE_ID_NAV));
			}
		});
	}

	public void registerProductModel(ProductModel productModel) {
		productModels.add(productModel);
		updateProductModel(productModel);
	}

	public void registerShiftChangeModel(ShiftChangeModel shiftChangeModel) {
		this.shiftChangeModel = shiftChangeModel;
		shiftChangeModel.addPropertyChangeListener("shiftChange", new PropertyChangeListener(){
			public void propertyChange(PropertyChangeEvent evt) {
				updateShiftChange();
			}
		});
	}
	public void registerShiftChangeWidget(ILazyWidget shiftChangeWidget) {
		shiftChangeWidget.addWidgetListener(new WidgetListenerAdapter() {
			@Override
			public void onAttach(IWidget widget) {
				shiftChangeModel.setShiftChange(new ShiftChange());
				updateShiftChange();
				SearchRequestImpl searchRequest = new SearchRequestImpl();
				searchRequest.setClassName(ShiftChange.class.getName());
				searchRequest.setLimit(1);
				searchRequest.setOffset(0);
				searchRequest.setSort(new Sort("date", false));
				searchRequest.setType(SearchRequest.TYPE_ALL);
				DataService.Util.getInstance().search(searchRequest, new AsyncCallback<SearchResult<ShiftChange>>(){
					public void onFailure(Throwable caught) {
					}
					public void onSuccess(SearchResult<ShiftChange> result) {
						List<ShiftChange> objects = result.getObjects();
						System.out.println("loading former shift change:"+objects);
						if(!objects.isEmpty())
							shiftChangeModel.setLastShiftChange(objects.get(0));
					}
				});
			}
		});
	}

	private void updateProductModel(ProductModel productModel) {
		ShiftChange shiftChange = shiftChangeModel.getShiftChange();
		Product product = productModel.getProduct();
		if(shiftChange != null){
			List<Sale> sales = shiftChange.getSales(product);
			if(sales != null && !sales.isEmpty())
				productModel.setSales(sales);
			List<Purchase> purchases = shiftChange.getPurchases(product);
			if(purchases != null && purchases != null)
				productModel.setPurchases(purchases);
			Stock stock = shiftChange.getStock(product);
			if(stock != null)
				productModel.setStock(stock);
		}
	}

	private void updateShiftChange() {
		ShiftChange shiftChange = shiftChangeModel.getShiftChange();
		if(shiftChange == null)
			return;
		employeeTextBoxModel.setText(shiftChange != null ? shiftChange.getEmployee() : null);
		dateTextBoxModel.setText(shiftChange != null ? DateUtilImpl.getInstance().formatDateSpanish(shiftChange.getDate()): null);
		for (ProductModel productModel : productModels) {
			updateProductModel(productModel);
		}
	}

}